/* * Copyright (C) 2010-2014 - Andreas Maier * CONRAD is developed as an Open Source project under the GNU General Public License (GPL). */ package edu.stanford.rsl.apps.gui; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GridBagConstraints; import java.awt.Rectangle; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.font.FontRenderContext; import java.awt.font.LineBreakMeasurer; import java.awt.font.TextLayout; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.lang.reflect.Field; import java.text.AttributedCharacterIterator; import java.text.AttributedString; import java.text.BreakIterator; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Set; import javax.swing.DropMode; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.ListSelectionModel; import javax.swing.TransferHandler; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableCellRenderer; import com.thoughtworks.qdox.JavaDocBuilder; import com.thoughtworks.qdox.model.JavaClass; import com.thoughtworks.qdox.model.JavaField; import edu.stanford.rsl.conrad.utils.CONRAD; import edu.stanford.rsl.conrad.utils.Configuration; import edu.stanford.rsl.conrad.utils.RegKeys; import edu.stanford.rsl.conrad.utils.UserUtil; public class RegistryEditor extends JPanel implements ActionListener { /** * */ private static final long serialVersionUID = -8853718009928894577L; private Configuration config; private JButton add; private JButton delete; private JButton showKeys; private JTable table; public RegistryEditor(Configuration config){ super(); this.config = config; } public void initGUI(){ this.setLayout(ConfigurationFrame.createSubPaneLayout()); this.setBackground(Color.WHITE); Set<String> keys = config.getRegistryKeys(); String [][] tableData = new String [keys.size()][2]; String [] label = {"Key", "Value"}; Iterator<String> iter = keys.iterator(); int i = 0; while (iter.hasNext()){ tableData[i][0] = iter.next(); tableData[i][1] = config.getRegistryEntry(tableData[i][0]); i++; } table = new JTable(); DefaultTableModel model = new DefaultTableModel(tableData, label); table.setModel(model); table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); table.setFillsViewportHeight(true); table.setDropMode(DropMode.ON); table.setPreferredScrollableViewportSize(new Dimension(495, 270)); table.setTransferHandler(new TransferHandler() { /** * */ private static final long serialVersionUID = 6224911732660417665L; public boolean canImport(TransferSupport support) { // for the demo, we'll only support drops (not clipboard paste) if (!support.isDrop()) { return false; } // we only import Strings and files if (!(support.isDataFlavorSupported(DataFlavor.stringFlavor)||support.isDataFlavorSupported(DataFlavor.javaFileListFlavor))) { return false; } return true; } @SuppressWarnings("unchecked") public boolean importData(TransferSupport support) { // if we can't handle the import, say so if (!canImport(support)) { return false; } // fetch the drop location JTable.DropLocation dl = (JTable.DropLocation) support .getDropLocation(); int row = dl.getRow(); // fetch the data and bail if this fails String data; try { data = (String) support.getTransferable().getTransferData( DataFlavor.stringFlavor); } catch (UnsupportedFlavorException e) { try { java.util.List<File> l = (java.util.List<File>) support.getTransferable().getTransferData(DataFlavor.javaFileListFlavor); data = l.get(0).getAbsolutePath(); } catch (UnsupportedFlavorException e1) { // TODO Auto-generated catch block e1.printStackTrace(); return false; } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); return false; } } catch (IOException e) { return false; } DefaultTableModel model = (DefaultTableModel) table.getModel(); model.setValueAt(data, row, 1); Rectangle rect = table.getCellRect(row, 0, false); if (rect != null) { table.scrollRectToVisible(rect); } return true; } }); JScrollPane scroll = new JScrollPane(table); add(scroll, ConfigurationFrame.createConstraints(1, 1, 3, 2, GridBagConstraints.NORTH, GridBagConstraints.BOTH, 0, 0, 0, 0)); add = new JButton("Add key"); add.addActionListener(this); delete = new JButton("Remove key"); delete.addActionListener(this); showKeys = new JButton("Show available keys"); showKeys.addActionListener(this); add(add, ConfigurationFrame.createConstraints(1, 0, 1, 1, GridBagConstraints.WEST, GridBagConstraints.NONE, 5, 0, 5, 0)); add(showKeys, ConfigurationFrame.createConstraints(2, 0, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.NONE, 5, 0, 5, 0)); add(delete, ConfigurationFrame.createConstraints(3, 0, 1, 1, GridBagConstraints.EAST, GridBagConstraints.NONE, 5, 0, 5, 0)); setOpaque(true); } public static void main(String [] args){ Configuration.loadConfiguration(); JFrame frame = new JFrame(); frame.add(new RegistryEditor(Configuration.getGlobalConfiguration())); frame.setVisible(true); frame.setSize(new Dimension(495, 270)); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } JFrame keysDescription; JTable descTable; public class MultilineTableCell implements TableCellRenderer { class CellArea extends DefaultTableCellRenderer { /** * */ private static final long serialVersionUID = 1L; private String text; protected int rowIndex; protected int columnIndex; protected JTable table; protected Font font; private int paragraphStart,paragraphEnd; private LineBreakMeasurer lineMeasurer; public CellArea(String s, JTable tab, int row, int column,boolean isSelected) { text = s; rowIndex = row; columnIndex = column; table = tab; font = table.getFont(); if (isSelected) { setForeground(table.getSelectionForeground()); setBackground(table.getSelectionBackground()); } } public void paintComponent(Graphics gr) { super.paintComponent(gr); if ( text != null && !text.isEmpty() ) { Graphics2D g = (Graphics2D) gr; if (lineMeasurer == null) { AttributedCharacterIterator paragraph = new AttributedString(text).getIterator(); paragraphStart = paragraph.getBeginIndex(); paragraphEnd = paragraph.getEndIndex(); FontRenderContext frc = g.getFontRenderContext(); lineMeasurer = new LineBreakMeasurer(paragraph,BreakIterator.getWordInstance(), frc); } float breakWidth = (float)table.getColumnModel().getColumn(columnIndex).getWidth(); float drawPosY = 0; // Set position to the index of the first character in the paragraph. lineMeasurer.setPosition(paragraphStart); // Get lines until the entire paragraph has been displayed. while (lineMeasurer.getPosition() < paragraphEnd) { // Retrieve next layout. A cleverer program would also cache // these layouts until the component is re-sized. TextLayout layout = lineMeasurer.nextLayout(breakWidth); // Compute pen x position. If the paragraph is right-to-left we // will align the TextLayouts to the right edge of the panel. // Note: this won't occur for the English text in this sample. // Note: drawPosX is always where the LEFT of the text is placed. float drawPosX = layout.isLeftToRight() ? 0 : breakWidth - layout.getAdvance(); // Move y-coordinate by the ascent of the layout. drawPosY += layout.getAscent(); // Draw the TextLayout at (drawPosX, drawPosY). layout.draw(g, drawPosX, drawPosY); // Move y-coordinate in preparation for next layout. drawPosY += layout.getDescent() + layout.getLeading(); } table.setRowHeight(rowIndex,(int) drawPosY); } } } public Component getTableCellRendererComponent( JTable table, Object value,boolean isSelected, boolean hasFocus, int row,int column ) { CellArea area = new CellArea(value.toString(),table,row,column,isSelected); return area; } } /** * Example for getting comments from a java file using qdox. * This requires access to the actual java file in the list of ressources. * (Use source folder as output folder for class files in eclipse) */ private void generateKeyTableFromSources(){ // read java sources to parser from qdox InputStream stream = RegKeys.class.getResourceAsStream("RegKeys.java"); InputStreamReader reader = new InputStreamReader(stream); JavaDocBuilder builder = new JavaDocBuilder(); builder.addSource(reader); // generate table with line wrapping cells in colum 2 final int wordWrapColumnIndex = 1; descTable = new JTable() { /** * */ private static final long serialVersionUID = 7516482246121817003L; public TableCellRenderer getCellRenderer(int row, int column) { if (column == wordWrapColumnIndex ) { return new MultilineTableCell(); } else { return super.getCellRenderer(row, column); } } }; // Use qdox parser to parse RegKeys sources JavaClass cls = builder.getClassByName("edu.stanford.rsl.conrad.utils.RegKeys"); // get list of fields JavaField[] fields = cls.getFields(); // build table model String [][] tableData = new String [fields.length][2]; String [] label = {"Key", "Description"}; int i = 0; for (JavaField field : fields){ tableData[i][0] = field.getName(); tableData[i][1] = field.getComment(); if (tableData[i][1] != null){ tableData[i][1] = field.getComment().replace("<BR>", "\n") .replace("<br>", "\n") .replace("<b>", "\n") .replace("</b>", "\n"); } else { tableData[i][1] = ""; } i++; } DefaultTableModel model = new DefaultTableModel(tableData, label); descTable.setModel(model); } private void generateKeyTableFromClassFiles(){ // get fields from class file Field[] declaredFields = RegKeys.class.getDeclaredFields(); List<Field> staticFields = new ArrayList<Field>(); // add only static fields for (Field field : declaredFields) { if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) { staticFields.add(field); } } descTable = new JTable(); // build table model String [][] tableData = new String [staticFields.size()][2]; String [] label = {"Key", "Description"}; int i = 0; for (Field field : staticFields){ tableData[i][0] = field.getName(); tableData[i][1] = "Comment unavailable. (Use source folder as output folder for class files in eclipse or include sources in jar file.)"; i++; } DefaultTableModel model = new DefaultTableModel(tableData, label); descTable.setModel(model); } public void actionPerformed(ActionEvent e) { if (e.getSource().equals(add)){ try { String key = UserUtil.queryString("Enter key name:", ""); DefaultTableModel model = (DefaultTableModel) table.getModel(); boolean found = false; for (int i = 0; i < model.getRowCount(); i++){ if (model.getValueAt(i, 0).equals(key)) found = true; } if (! found) { model.addRow(new String [] {key, ""}); model.fireTableDataChanged(); } } catch (Exception e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } if (e.getSource().equals(showKeys)){ try { if (keysDescription ==null){ keysDescription = new JFrame("Available Keys"); keysDescription.setSize(640,480); keysDescription.setBackground(Color.WHITE); try{ // Read key descriptions from source file // getting comments requires access to the actual java files in the // resource path. generateKeyTableFromSources(); } catch (Exception e2){ // Generate key list using introspection only // will be executed if source is not found. generateKeyTableFromClassFiles(); } descTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); descTable.setFillsViewportHeight(true); descTable.setPreferredScrollableViewportSize(new Dimension(640, 480)); keysDescription.add(new JScrollPane(descTable)); keysDescription.setVisible(true); keysDescription.setLocation(CONRAD.getWindowTopCorner()); System.out.println("created"); } else { if( keysDescription.isVisible()){ keysDescription.setVisible(false); keysDescription = null; } else { keysDescription.setVisible(true); } } } catch (Exception e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } if (e.getSource().equals(delete)){ if (table.getSelectedRowCount() == 1){ DefaultTableModel model = (DefaultTableModel) table.getModel(); int selectedRow = table.getSelectedRow(); model.removeRow(selectedRow); } else { // won't delete multiple keys at once. table.getSelectionModel().clearSelection(); } } } public void updateToConfiguration(){ config.resetRegistry(); DefaultTableModel model = (DefaultTableModel) table.getModel(); int lenght = model.getRowCount(); for (int i = 0; i < lenght; i++){ config.setRegistryEntry((String) model.getValueAt(i, 0), (String) model.getValueAt(i, 1)); } } }